<template>
  <el-card class="editor-card">
    <template #header>
      <div class="editor-header">
        <div class="editor-title">评估报告编辑</div>
        <el-button @click="goBack" :disabled="!version.report_id">返回</el-button>
      </div>
    </template>
    <div class="info-row">
      <span class="info-item">报告主版：</span>
      <span class="name">{{ header.name }}</span>
      <span class="code">{{ header.code }}</span>
      <span class="info-sep">｜</span>
      <span class="info-item">版本号：{{ version.version_no }}</span>
      <span class="info-sep">｜</span>
      <span class="info-item">评估模板：</span>
      <span class="name">{{ templateName }}</span>
      <span class="code">{{ version.template_version_code }}</span>
    </div>
    <el-row :gutter="12" class="editor-row">
      <el-col :span="5">
        <el-card class="panel-card">
          <template #header>
            <div class="panel-header">
              <span>章节目录</span>
              <el-button  @click="toggleOutline">{{ outlineExpanded ? '收起' : '展开' }}</el-button>
            </div>
          </template>
          <div class="panel-content">
            <el-tree
              :key="outlineExpanded ? 'exp' : 'col'"
              :data="outlineTree"
              node-key="section_no"
              :default-expanded-keys="outlineExpanded ? allSectionKeys : []"
              :props="{ label:'section_name', children:'children' }"
              :expand-on-click-node="false"
              @node-click="selectSection"
            >
              <template #default="{ data }">
                <span>{{ data.section_no }} {{ data.section_name }}</span>
              </template>
            </el-tree>
          </div>
        </el-card>
      </el-col>
      <el-col :span="19">
        <el-card class="panel-card">
          <template #header>
            <div class="panel-header">
              <span>{{ viewMode === 'generate' ? '内容生成' : '内容预览' }}</span>
              <span v-if="viewMode==='generate' && currentSection" class="active-section">{{ currentSection.section_no }} {{ currentSection.section_name }}</span>
              <div class="panel-actions">
                <el-button v-if="viewMode==='preview'" type="primary" @click="openExportDialog">生成文件</el-button>
                <el-button @click="toggleViewMode">{{ viewMode==='generate' ? '切换到预览模式' : '切换到生成模式' }}</el-button>
                <el-button v-if="viewMode==='preview'" @click="toggleAllPreview">{{ previewExpandLabel }}</el-button>
              </div>
            </div>
          </template>
          <div class="panel-content">
      <template v-if="viewMode==='generate'">
              <div class="gen-layout">
                <div class="chat-sidenav">
                  <div class="sidenav-header">
                    <el-button type="primary" @click="createConversation" :disabled="!currentSection">新建任务</el-button>
                  </div>
                  <div class="sidenav-list">
                    <div
                      v-for="c in conversationTasks"
                      :key="c.id"
                      :class="['conv-item', c.id===currentConversationId ? 'conv-active' : '']"
                      @click="selectConversation(c)"
                    >
                      <div class="conv-body">
                        <template v-if="c.editing">
                          <el-input v-model="c.titleEditing" size="small" @keydown.enter="commitRename(c)" @blur="commitRename(c)" />
                        </template>
                        <template v-else>
                          <div class="conv-title">{{ c.title }}</div>
                          <div class="conv-meta">{{ c.meta }}</div>
                        </template>
                      </div>
                      <div class="conv-actions">
                        <el-dropdown @command="(cmd)=>handleConvCommand(cmd, c)">
                          <span class="el-dropdown-link">
                            <el-button text size="small" @click.stop>...</el-button>
                          </span>
                          <template #dropdown>
                            <el-dropdown-menu>
                              <el-dropdown-item command="rename">重命名</el-dropdown-item>
                              <el-dropdown-item command="delete">删除</el-dropdown-item>
                            </el-dropdown-menu>
                          </template>
                        </el-dropdown>
                      </div>
                    </div>
                  </div>
                </div>
                <div class="chat-main">
                  <div class="chat-history" ref="historyEl">
                    <div class="message-list">
                      <div v-for="m in currentMessages" :key="m.id" :class="['msg', m.role==='user' ? 'msg-user' : 'msg-assistant', m.pending ? 'msg-pending' : '']">
                        <div v-if="m.role==='user'" class="msg-menu">
                          <el-button text size="small">...</el-button>
                          <div class="menu-buttons">
                            <el-button text size="small" @click="copyPromptFromMessage(m)">复制</el-button>
                            <el-button text size="small" type="danger" @click="deleteMessagePair(m)">删除</el-button>
                          </div>
                        </div>
                        <div v-if="m.role==='assistant' && m.candidate_id" class="msg-menu msg-menu-right">
                          <el-button text size="small">...</el-button>
                          <div class="menu-buttons">
                            <el-button text size="small" @click="adoptFromMessage(m)">采用</el-button>
                          </div>
                        </div>
                        <div v-if="m.html" class="msg-text" v-html="m.html"></div>
                        <div v-else class="msg-text">{{ m.text }}</div>
                      </div>
                    </div>
                  </div>
                  <div class="chat-input">
                    <div class="rich-textarea" ref="promptEl" contenteditable="true" @input="onPromptInput"></div>
                    <div class="chat-toolbar">
                      <div class="toolbar-left">
                        <el-dropdown @command="insertHashtag">
                          <span class="el-dropdown-link">
                            <el-button>#</el-button>
                          </span>
                          <template #dropdown>
                            <el-dropdown-menu>
                              <el-dropdown-item command="活动">活动</el-dropdown-item>
                              <el-dropdown-item command="事件">事件</el-dropdown-item>
                              <el-dropdown-item command="活动评估（指标和得分）">活动评估（指标和得分）</el-dropdown-item>
                              <el-dropdown-item command="网址">网址</el-dropdown-item>
                            </el-dropdown-menu>
                          </template>
                        </el-dropdown>
                        <el-upload class="upload-inline" :show-file-list="true" :auto-upload="false" :http-request="handleUpload" :accept="acceptTypes">
                          <el-button >附件</el-button>
                        </el-upload>
                      </div>
                      <div class="toolbar-right">
                        <el-select v-model="modelId" placeholder="选择模型" style="width:240px">
                          <el-option v-for="m in models" :key="m.id" :label="m.display_name" :value="m.id" />
                        </el-select>
                        <el-button type="primary" @click="sendPrompt" :disabled="sendDisabled">发送</el-button>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </template>
            <template v-else>
              <div class="report-preview" ref="previewEl">
                <div
                  v-for="s in outlineSorted"
                  :key="s.section_no"
                  :id="'section-' + s.section_no"
                  :class="['section', 'l' + (s.level || 1)]"
                >
                  <div class="title-row" @click="toggleSection(s)">
                    <span class="caret">{{ isCollapsed(s) ? '▶' : '▼' }}</span>
                    <div :class="titleClass(s.level)">{{ s.section_no }} {{ s.section_name }}</div>
                  </div>
                  <div v-show="!isCollapsed(s)">
                    <div v-if="sectionContents[s.section_no]" class="section-content" v-html="sectionContents[s.section_no]"></div>
                    <el-input v-else type="textarea" :rows="s.level===1?4:s.level===2?3:2" placeholder="（此处为已采用内容预览占位）" />
                  </div>
                </div>
              </div>
            </template>
            <el-dialog v-model="activityDialogVisible" title="选择活动" width="600px">
              <div class="activity-picker">
                <el-table :data="activityList" height="360" v-loading="activityLoading">
                  <el-table-column prop="name" label="活动名称" />
                  <el-table-column label="操作" width="120">
                    <template #default="{ row }">
                      <el-button size="small" type="primary" @click="chooseActivity(row)">选择</el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
              <template #footer>
                <el-button @click="activityDialogVisible=false">关闭</el-button>
              </template>
            </el-dialog>
            <el-dialog v-model="eventDialogVisible" title="选择事件" width="600px">
              <div class="event-picker">
                <el-table :data="eventList" height="360" v-loading="eventLoading">
                  <el-table-column prop="name" label="事件名称" />
                  <el-table-column label="操作" width="120">
                    <template #default="{ row }">
                      <el-button size="small" type="primary" @click="chooseEvent(row)">选择</el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
              <template #footer>
                <el-button @click="eventDialogVisible=false">关闭</el-button>
              </template>
            </el-dialog>
            <el-dialog v-model="urlDialogVisible" title="添加网址" width="480px">
              <el-input v-model="urlInput" placeholder="输入网址" />
              <template #footer>
                <el-button @click="urlDialogVisible=false">取消</el-button>
                <el-button type="primary" @click="confirmUrl">确定</el-button>
              </template>
            </el-dialog>
            <el-dialog v-model="exportDialogVisible" title="生成文件" width="480px">
              <el-radio-group v-model="exportType">
                <el-radio label="docx">Word（.docx）</el-radio>
                <el-radio label="pdf">PDF（.pdf）</el-radio>
              </el-radio-group>
              <div v-if="exportResultPath" style="margin-top:12px;">
                <el-alert type="success" :closable="false" title="已生成" :description="exportResultPath" />
              </div>
              <template #footer>
                <el-button @click="exportDialogVisible=false">取消</el-button>
                <el-button type="primary" :loading="exportLoading" @click="confirmExport">确定</el-button>
              </template>
            </el-dialog>
          </div>
        </el-card>
      </el-col>
    </el-row>
  </el-card>
</template>

<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { api } from '../../api/client'

const route = useRoute()
const router = useRouter()
const versionId = route.params.versionId as string
const header = ref<any>({ code:'', name:'' })
const version = ref<any>({})
const outlineTree = ref<any[]>([])
const currentSection = ref<any>(null)
const outlineExpanded = ref(true)
const allSectionKeys = ref<string[]>([])
const models = ref<any[]>([])
const modelId = ref('')
const prompt = ref('')
const candidates = ref<any[]>([])
const previewHtml = ref('')
const templateName = ref('')
const viewMode = ref<'generate'|'preview'>('generate')
const sectionContents = ref<Record<string,string>>({})

const conversationTasks = ref<any[]>([])
const currentConversationId = ref<string>('')
const historyEl = ref<HTMLDivElement|null>(null)
const acceptTypes = ref('image/*,.doc,.docx,.pdf')
const uploadedFiles = ref<any[]>([])
const selectedActivity = ref<any>(null)
const activityDialogVisible = ref(false)
const activityList = ref<any[]>([])
const activityLoading = ref(false)
const selectedContext = ref<any[]>([])
const eventDialogVisible = ref(false)
const eventList = ref<any[]>([])
const eventLoading = ref(false)
const urlDialogVisible = ref(false)
const urlInput = ref('')
const exportDialogVisible = ref(false)
const exportType = ref<'docx'|'pdf'>('docx')
const exportLoading = ref(false)
const exportResultPath = ref('')
const promptEl = ref<HTMLDivElement|null>(null)
const savedRange = ref<Range|null>(null)
const currentMessages = computed(()=>{
  const c = conversationTasks.value.find(x=>x.id===currentConversationId.value)
  const list = Array.isArray(c?.messages) ? c.messages : []
  return list
})
const sendDisabled = computed(()=>{
  const text = String(prompt.value || '').trim()
  return !currentSection.value || !currentConversationId.value || !modelId.value || !text
})

// 预览模式所需：基于扁平大纲构建折叠与滚动
const outlineFlat = ref<any[]>([])
const outlineSorted = computed(() => [...(outlineFlat.value || [])].sort((a,b)=>String(a.section_no).localeCompare(String(b.section_no))))
const collapsedSet = ref<Set<string>>(new Set())
const previewExpandedAll = ref(true)
const previewEl = ref<HTMLDivElement|null>(null)

function isCollapsed(s:any){ return collapsedSet.value.has(String(s.section_no)) }
function toggleSection(s:any){
  const k = String(s.section_no)
  if(collapsedSet.value.has(k)) collapsedSet.value.delete(k); else collapsedSet.value.add(k)
  collapsedSet.value = new Set(Array.from(collapsedSet.value))
}
function scrollToSection(no:string){
  const container = previewEl.value
  const el = document.getElementById(`section-${no}`)
  if(!container || !el) return
  const k = String(no)
  if(collapsedSet.value.has(k)){
    const next = new Set(collapsedSet.value); next.delete(k); collapsedSet.value = next
  }
  const cRect = container.getBoundingClientRect()
  const eRect = el.getBoundingClientRect()
  const top = container.scrollTop + (eRect.top - cRect.top) - 8
  container.scrollTo({ top, behavior: 'smooth' })
}
const previewExpandLabel = computed(()=> previewExpandedAll.value ? '收起预览' : '展开预览')
function toggleAllPreview(){
  previewExpandedAll.value = !previewExpandedAll.value
  if(previewExpandedAll.value){ collapsedSet.value = new Set() } else {
    collapsedSet.value = new Set((outlineFlat.value || []).map((s:any)=>String(s.section_no)))
  }
}
function titleClass(level:number){
  if(level===1) return 'h1'
  if(level===2) return 'h2'
  return 'h3'
}

function toggleViewMode(){
  viewMode.value = viewMode.value === 'generate' ? 'preview' : 'generate'
  if(viewMode.value==='preview' && currentSection.value){
    scrollToSection(currentSection.value.section_no)
    loadAllSectionContents()
  }
}

async function loadBasic(){
  const v = await api.get(`/report-versions/${versionId}`)
  version.value = v.data
  const hs = await api.get('/report-headers/')
  const hdata = hs.data
  const headers = Array.isArray(hdata?.items) ? hdata.items : Array.isArray(hdata) ? hdata : []
  header.value = headers.find((x:any)=>x.id===version.value.report_id) || { code:'', name:'' }
}

async function loadTemplateName(){
  if(!version.value?.template_version_code) return
  const { data } = await api.get('/evaluation-templates')
  const list = Array.isArray(data?.items) ? data.items : Array.isArray(data) ? data : []
  const found = list.find((t:any)=>t.template_version_code===version.value.template_version_code)
  templateName.value = found?.name || ''
}

async function loadOutline(){
  const { data } = await api.get(`/template-outline/${version.value.template_version_code}`)
  outlineTree.value = buildTree(data.outline)
  outlineFlat.value = Array.isArray(data.outline) ? data.outline : []
  allSectionKeys.value = Array.isArray(data.outline) ? data.outline.map((x:any)=>x.section_no) : []
}

function buildTree(list:any[]){
  const nodes = list.map(x=>({ ...x, children: [] }))
  const root:any[] = []
  const map:Record<string,any> = {}
  nodes.forEach(n=>map[n.section_no]=n)
  nodes.forEach(n=>{
    const p = n.section_no.includes('.') ? n.section_no.slice(0, n.section_no.lastIndexOf('.')) : ''
    if(p && map[p]) map[p].children.push(n); else root.push(n)
  })
  return root
}

function selectSection(node:any){
  currentSection.value = node
  candidates.value = []
  if(viewMode.value==='preview') scrollToSection(node.section_no)
  loadTasks()
}

async function loadModels(){
  const { data } = await api.get('/llm/models')
  models.value = data
}

async function loadAllSectionContents(){
  const { data } = await api.get(`/report-content/${versionId}/sections/contents`)
  const items = Array.isArray(data?.items) ? data.items : []
  const map: Record<string,string> = {}
  for(const it of items){
    if(it && it.section_no){ map[String(it.section_no)] = String(it.final_text || '') }
  }
  sectionContents.value = map
}

async function generate(){
  const { data } = await api.post(`/report-content/${versionId}/sections/${currentSection.value.section_no}/generate`, {
    model_id: modelId.value,
    prompt: prompt.value,
  })
  candidates.value = data.candidates || []
}

async function adopt(row:any){
  await api.post(`/report-content/${versionId}/sections/${currentSection.value.section_no}/adopt`, {
    candidate_id: row.candidate_id
  })
  const prev = await api.get(`/report-content/${versionId}/preview`)
  previewHtml.value = prev.data.html || ''
  await loadAllSectionContents()
}

function createConversation(){
  if(!currentSection.value) return
  const title = `${currentSection.value.section_no} ${currentSection.value.section_name}`
  createTask(title)
}

function selectConversation(c:any){
  currentConversationId.value = c.id
  loadMessagesInitial()
}

function startRename(c:any){
  c.editing = true
  c.titleEditing = c.title
}

function commitRename(c:any){
  const t = String(c.titleEditing || '').trim()
  if(t) c.title = t
  c.editing = false
  if(c?.id) updateTaskTitle(c.id, t)
}

function insertHashtag(cmd:string){
  const v = cmd || ''
  if(v==='活动'){
    openActivityPicker()
    return
  }
  if(v==='事件'){
    openEventPicker()
    return
  }
  if(v==='网址'){
    openUrlDialog()
    return
  }
  prompt.value = `${prompt.value || ''}#${v} `
}

function handleUpload(options:any){
  const { file } = options
  uploadedFiles.value.push(file)
}

async function sendPrompt(){
  if(!currentSection.value || !currentConversationId.value) return
  const content = String(prompt.value || '').trim()
  if(!content || !modelId.value) return
  const conv = conversationTasks.value.find(x=>x.id===currentConversationId.value)
  if(!conv) return
  if(!Array.isArray(conv.messages)) conv.messages = []
  const total = conv.messages.length
  if(total >= 50){
    createConversation()
    return sendPrompt()
  }
  const html = String(promptEl.value?.innerHTML || '')
  const userId = `${Date.now()}-u`
  conv.messages.push({ id: userId, role: 'user', text: content, html })
  const pendingId = `${Date.now()}-p`
  conv.messages.push({ id: pendingId, role: 'assistant', text: '正在生成...', pending: true })
  if(historyEl.value){ historyEl.value.scrollTop = historyEl.value.scrollHeight }
  try{
    const { data } = await api.post(`/report-content/${versionId}/sections/${currentSection.value.section_no}/generate`, {
      model_id: modelId.value,
      prompt: content,
      activity: selectedActivity.value || undefined,
      context: selectedContext.value.map((x:any)=>({ type: x.type, id: x.id, name: x.name, payload: x.payload })),
      conversation_id: conv.conversation_id
    })
    candidates.value = data.candidates || []
    const list = Array.isArray(data.candidates) ? data.candidates : []
    const msgIds = (data?.message_ids) || {}
    const idx = conv.messages.findIndex((m:any)=>m.id===pendingId)
    if(idx>=0){
      if(list.length){
        conv.messages[idx] = { id: pendingId, role: 'assistant', text: list[0].text, candidate_id: list[0].candidate_id }
      } else {
        conv.messages[idx] = { id: pendingId, role: 'assistant', text: '(无生成结果)' }
      }
    }
    const uIdx = conv.messages.findIndex((m:any)=>m.id===userId)
    if(uIdx>=0 && msgIds.user_msg_id){ conv.messages[uIdx].id = msgIds.user_msg_id }
    if(idx>=0 && msgIds.assistant_msg_id){ conv.messages[idx].id = msgIds.assistant_msg_id }
    for(let i=1;i<list.length;i++){
      const it = list[i]
      conv.messages.push({ id: `${Date.now()}-a-${i}`, role: 'assistant', text: it.text, candidate_id: it.candidate_id })
    }
  } catch(err:any){
    const idx = conv.messages.findIndex((m:any)=>m.id===pendingId)
    if(idx>=0){ conv.messages[idx] = { id: pendingId, role: 'assistant', text: `生成失败：${String(err?.message||err)}` } }
  } finally {
    prompt.value = ''
    if(promptEl.value){ promptEl.value.innerHTML = '' }
    savedRange.value = null
    if(historyEl.value){ historyEl.value.scrollTop = historyEl.value.scrollHeight }
  }
}

async function openActivityPicker(){
  saveCaret()
  activityDialogVisible.value = true
  activityLoading.value = true
  try{
    const { data } = await api.get('/activities/')
    activityList.value = Array.isArray(data) ? data : []
  } finally {
    activityLoading.value = false
  }
}

function chooseActivity(row:any){
  selectedActivity.value = row
  activityDialogVisible.value = false
  setContext('activity', row?.id, row?.name, row)
  insertContextTag('activity', row?.id, row?.name)
}

async function openEventPicker(){
  saveCaret()
  eventDialogVisible.value = true
  eventLoading.value = true
  try{
    const { data } = await api.get('/events/')
    eventList.value = Array.isArray(data) ? data : []
  } finally {
    eventLoading.value = false
  }
}

function openUrlDialog(){
  saveCaret()
  urlDialogVisible.value = true
}

function openExportDialog(){
  exportResultPath.value = ''
  exportType.value = 'docx'
  exportDialogVisible.value = true
}

function chooseEvent(row:any){
  setContext('event', row?.id, row?.name, row)
  insertContextTag('event', row?.id, row?.name)
  eventDialogVisible.value = false
}

function confirmUrl(){
  const u = String(urlInput.value || '').trim()
  if(u){ setContext('url', u, u, { url: u }); insertContextTag('url', u, u) }
  urlInput.value = ''
  urlDialogVisible.value = false
}

async function confirmExport(){
  if(!version.value?.id && !route.params.versionId) return
  try{
    exportLoading.value = true
    const { data } = await api.post(`/report-content/${versionId}/export`, { type: exportType.value })
    exportResultPath.value = String(data?.file_url || '')
  } finally {
    exportLoading.value = false
  }
}

function setContext(type:string, id:any, name:string, payload:any){
  const label = type==='activity' ? '活动' : type==='event' ? '事件' : type==='url' ? '网址' : type
  const existingIndex = selectedContext.value.findIndex((x:any)=>x.type===type)
  const rec = { type, id, name, payload, typeLabel: label }
  if(existingIndex>=0) selectedContext.value.splice(existingIndex,1, rec); else selectedContext.value.push(rec)
}

function removeContext(type:string){
  const i = selectedContext.value.findIndex((x:any)=>x.type===type)
  if(i>=0) selectedContext.value.splice(i,1)
}

function tagType(type:string){
  if(type==='activity') return 'success'
  if(type==='event') return 'warning'
  if(type==='url') return 'info'
  return ''
}

function onPromptInput(){
  prompt.value = String(promptEl.value?.innerText || '')
}

function insertContextTag(type:string, id:any, name:string){
  const el = promptEl.value
  if(!el) return
  const span = document.createElement('span')
  span.className = 'ctx-tag'
  span.setAttribute('data-type', String(type))
  span.setAttribute('data-id', String(id||''))
  span.contentEditable = 'false'
  const btn = document.createElement('button')
  btn.className = 'ctx-remove'
  btn.type = 'button'
  btn.textContent = '×'
  btn.onclick = ()=>{ removeContextTag(span) }
  const label = document.createElement('span')
  label.className = 'ctx-label'
  label.textContent = `${typeLabel(type)}：${name || ''}`
  span.appendChild(btn)
  span.appendChild(label)
  const space = document.createTextNode(' ')
  const sel = window.getSelection()
  let range: Range | null = null
  if(savedRange.value){
    range = savedRange.value.cloneRange()
  } else if(sel && sel.rangeCount>0 && el.contains(sel.anchorNode as Node)){
    range = sel.getRangeAt(0)
  }
  if(range){
    range.insertNode(space)
    range.insertNode(span)
    range.setStartAfter(space)
    range.setEndAfter(space)
    sel?.removeAllRanges()
    sel?.addRange(range)
    savedRange.value = range.cloneRange()
  } else {
    el.appendChild(span)
    el.appendChild(space)
    const r = document.createRange()
    r.selectNodeContents(el)
    r.collapse(false)
    sel?.removeAllRanges()
    sel?.addRange(r)
    savedRange.value = r.cloneRange()
  }
  onPromptInput()
}

function removeContextTag(span:HTMLElement){
  const type = span.getAttribute('data-type') || ''
  span.remove()
  removeContext(type)
  onPromptInput()
}

function typeLabel(type:string){
  if(type==='activity') return '活动'
  if(type==='event') return '事件'
  if(type==='url') return '网址'
  return type
}

function updateSavedRange(){
  const el = promptEl.value
  const sel = window.getSelection()
  if(!el || !sel || sel.rangeCount===0) return
  const r = sel.getRangeAt(0)
  if(el.contains(r.startContainer)) savedRange.value = r.cloneRange()
}

function saveCaret(){
  updateSavedRange()
  if(!savedRange.value && promptEl.value){
    const r = document.createRange()
    r.selectNodeContents(promptEl.value)
    r.collapse(false)
    savedRange.value = r
  }
}

async function adoptFromMessage(m:any){
  if(!m?.candidate_id) return
  await adopt({ candidate_id: m.candidate_id })
}

function deleteConversation(c:any){
  const idx = conversationTasks.value.findIndex(x=>x.id===c.id)
  if(idx>=0){
    const removed = conversationTasks.value.splice(idx,1)[0]
    if(removed?.id===currentConversationId.value){
      const next = conversationTasks.value[0]
      currentConversationId.value = next ? next.id : ''
    }
  }
  if(c?.id) deleteTask(c.id)
}

function handleConvCommand(cmd:string, c:any){
  if(cmd==='rename') startRename(c)
  else if(cmd==='delete') deleteConversation(c)
}

function goBack(){
  if(!version.value?.report_id) return
  router.push(`/admin/report-headers/${version.value.report_id}/versions`)
}

function toggleOutline(){
  outlineExpanded.value = !outlineExpanded.value
}

onMounted(async()=>{ await loadBasic(); await loadTemplateName(); await loadOutline(); await loadModels() })
async function loadTasks(){
  if(!currentSection.value) return
  const { data } = await api.get(`/report-content/${versionId}/sections/${currentSection.value.section_no}/tasks`)
  const items = Array.isArray(data?.items) ? data.items : []
  conversationTasks.value = items.map((x:any)=>({ id: x.id, conversation_id: x.conversation_id, title: x.title, meta: x.meta, section_no: currentSection.value.section_no, messages: [], paging: { limit: 20, hasMore: true, nextBefore: null as string | null, loading: false, initialized: false } }))
  const first = conversationTasks.value[0]
  currentConversationId.value = first ? first.id : ''
  if(first) loadMessagesInitial()
}

onMounted(()=>{
  const el = promptEl.value
  if(!el) return
  el.addEventListener('keyup', updateSavedRange)
  el.addEventListener('mouseup', updateSavedRange)
  el.addEventListener('focus', updateSavedRange)
})

async function createTask(title:string){
  const { data } = await api.post(`/report-content/${versionId}/sections/${currentSection.value.section_no}/tasks`, { title })
  const rec = { id: data.id, conversation_id: data.conversation_id, title: data.title, meta: data.meta, section_no: currentSection.value.section_no, messages: [], paging: { limit: 20, hasMore: true, nextBefore: null as string | null, loading: false, initialized: false } }
  conversationTasks.value.unshift(rec)
  currentConversationId.value = rec.id
}

async function updateTaskTitle(taskId:string, title:string){
  await api.put(`/report-content/${versionId}/sections/${currentSection.value.section_no}/tasks/${taskId}`, { title })
}

async function deleteTask(taskId:string){
  await api.delete(`/report-content/${versionId}/sections/${currentSection.value.section_no}/tasks/${taskId}`)
}

async function loadMessagesInitial(){
  const conv = conversationTasks.value.find(x=>x.id===currentConversationId.value)
  if(!conv || conv.paging?.loading) return
  conv.paging.loading = true
  try{
    const { data } = await api.get(`/report-content/${versionId}/sections/${currentSection.value.section_no}/tasks/${conv.id}/messages`, { params: { limit: conv.paging.limit } })
    const items = Array.isArray(data?.items) ? data.items : []
    conv.messages = items.map((m:any)=>({ id: m.msg_id, role: m.role, text: m.text, candidate_id: m.candidate_id, created_at: m.created_at }))
    conv.paging.hasMore = !!data?.has_more
    conv.paging.nextBefore = data?.next_before || null
    conv.paging.initialized = true
    if(historyEl.value){ historyEl.value.scrollTop = historyEl.value.scrollHeight }
  } finally {
    conv.paging.loading = false
  }
}

async function loadMoreMessages(){
  const conv = conversationTasks.value.find(x=>x.id===currentConversationId.value)
  if(!conv || conv.paging?.loading || !conv.paging?.hasMore) return
  const before = conv.paging.nextBefore
  if(!before) return
  conv.paging.loading = true
  const el = historyEl.value
  const prevHeight = el ? el.scrollHeight : 0
  try{
    const { data } = await api.get(`/report-content/${versionId}/sections/${currentSection.value.section_no}/tasks/${conv.id}/messages`, { params: { limit: conv.paging.limit, before } })
    const items = Array.isArray(data?.items) ? data.items : []
    const merged = items.map((m:any)=>({ id: m.msg_id, role: m.role, text: m.text, candidate_id: m.candidate_id, created_at: m.created_at }))
    conv.messages = [...merged, ...conv.messages]
    conv.paging.hasMore = !!data?.has_more
    conv.paging.nextBefore = data?.next_before || null
    if(el){
      const newHeight = el.scrollHeight
      el.scrollTop = newHeight - prevHeight
    }
  } finally {
    conv.paging.loading = false
  }
}

function toPlainText(html:string){
  const div = document.createElement('div')
  div.innerHTML = html || ''
  return String(div.textContent || div.innerText || '')
}

function copyPromptFromMessage(m:any){
  const t = m.html ? toPlainText(String(m.html||'')) : String(m.text||'')
  const content = t.trim()
  prompt.value = content
  if(promptEl.value){
    promptEl.value.innerText = content
    const r = document.createRange()
    r.selectNodeContents(promptEl.value)
    r.collapse(false)
    savedRange.value = r
  }
}

async function deleteMessagePair(m:any){
  if(!m || m.role !== 'user') return
  const conv = conversationTasks.value.find(x=>x.id===currentConversationId.value)
  if(!conv) return
  try{
    await api.delete(`/report-content/${versionId}/sections/${currentSection.value.section_no}/tasks/${conv.id}/messages/${m.id}`)
  } finally {
    const idx = conv.messages.findIndex((x:any)=>x.id===m.id)
    if(idx>=0){
      let end = idx + 1
      while(end < conv.messages.length && conv.messages[end].role === 'assistant'){ end++ }
      conv.messages.splice(idx, end - idx)
    }
  }
}

onMounted(()=>{
  const h = historyEl.value
  if(!h) return
  h.addEventListener('scroll', ()=>{
    if(h.scrollTop === 0){
      loadMoreMessages()
    }
  })
})
</script>

<style scoped>
.editor-header { display: flex; align-items: center; justify-content: space-between; }
.editor-title { font-weight: 600; }
.info-row { margin-top: 0px; margin-bottom: 8px; font-size: 13px; line-height: 1.6; color: #606266; display: flex; align-items: center; gap: 6px; padding: 6px 10px; background: #f7f8fa; border: 1px solid #ebeef5; border-radius: 8px; }
.info-item { white-space: nowrap; }
.info-sep { margin: 0 4px; color: #c0c4cc; }
.name { font-weight: 600; color: #303133; }
.code { margin-left: 4px; color: #909399; background: #f0f2f5; border: 1px solid #e4e7ed; border-radius: 4px; padding: 2px 6px; font-size: 12px; }
.editor-row { flex: 1; display: flex; min-height: 0; }
.editor-row .el-col { height: 100%; display: flex; flex-direction: column; min-height: 0; }
.panel-card { display: flex; flex-direction: column; flex: 1; }
.panel-card :deep(.el-card__body){ display: flex; flex-direction: column; flex: 1; min-height: 0; }
.panel-header { display: flex; align-items: center; justify-content: space-between; }
.active-section { margin-left: 12px; color: #f56c6c; font-weight: 700; }
.panel-content { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
.panel-content :deep(.el-tree){ flex: 1; min-height: 0; overflow: auto; }
.gen-toolbar { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.gen-layout { display: flex; gap: 12px; flex: 1; min-height: 0; }
.chat-sidenav { width: 20%; min-width: 220px; display: flex; flex-direction: column; gap: 8px; }
.sidenav-header { display: flex; justify-content: flex-start; }
.sidenav-list { flex: 1; min-height: 0; overflow: auto; border: 1px solid #ebeef5; border-radius: 6px; padding: 8px; background: #fff; }
.conv-item { padding: 8px; border-radius: 6px; cursor: pointer; }
.conv-item { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.conv-body { flex: 1; min-width: 0; }
.conv-actions { display: flex; align-items: center; gap: 6px; }
.conv-item:hover { background: #f7f8fa; }
.conv-active { background: #eef5ff; border: 1px solid #cfe2ff; }
.conv-title { font-weight: 600; color: #303133; }
.conv-meta { font-size: 12px; color: #909399; margin-top: 2px; }
.chat-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.chat-history { flex: 1; min-height: 0; overflow: auto; border: 1px solid #ebeef5; border-radius: 6px; padding: 8px; background: #fff; }
.message-list { display: flex; flex-direction: column; gap: 8px; }
.msg { display: flex; flex-direction: column; gap: 4px; max-width: 80%; position: relative; }
.msg-user { align-self: flex-end; }
.msg-assistant { align-self: flex-start; }
.msg-user .msg-text { background: #eef2f6; }
.msg-assistant .msg-text { background: #f5f7fa; }
.msg-pending .msg-text { color: #909399; font-style: italic; }
.msg-text { white-space: pre-wrap; word-break: break-word; border: 1px solid #ebeef5; border-radius: 6px; padding: 8px; height: 180px; overflow-y: auto; }
.msg-actions { display: flex; align-items: center; gap: 6px; margin-top: 6px; padding-top: 6px; border-top: 1px dashed #eaeaea; }
.msg-menu { position: absolute; left: 0; top: 0; transform: translateX(-100%); display: flex; align-items: center; gap: 6px; }
.msg-menu .menu-buttons { display: none; gap: 2px; }
.msg-menu:hover .menu-buttons { display: inline-flex; }
.msg-menu-right { left: auto; right: 0; transform: translateX(100%); }
.section-content { white-space: pre-wrap; word-break: break-word; border: 1px solid #ebeef5; border-radius: 6px; padding: 8px; background: #fff; }
.chat-input { display: flex; flex-direction: column; gap: 8px; }
.rich-textarea { border: 1px solid #ebeef5; border-radius: 6px; padding: 8px; height: 180px; background: #fff; overflow-y: auto; white-space: pre-wrap; word-break: break-word; line-height: 1.6; }
.rich-textarea :deep(.ctx-tag), .msg-text :deep(.ctx-tag) { display: inline-flex; align-items: center; gap: 6px; border-radius: 9999px; padding: 2px 8px; font-size: 13px; border: 1px solid transparent; vertical-align: middle; }
.rich-textarea :deep(.ctx-tag[data-type="activity"]), .msg-text :deep(.ctx-tag[data-type="activity"]) { background: #f0f9eb; border-color: #e1f3d8; color: #67C23A; }
.rich-textarea :deep(.ctx-tag[data-type="event"]), .msg-text :deep(.ctx-tag[data-type="event"]) { background: #fdf6ec; border-color: #faecd8; color: #E6A23C; }
.rich-textarea :deep(.ctx-tag[data-type="url"]), .msg-text :deep(.ctx-tag[data-type="url"]) { background: #eef2f6; border-color: #e4e7ed; color: #909399; }
.rich-textarea :deep(.ctx-remove), .msg-text :deep(.ctx-remove) { display: inline-flex; align-items: center; justify-content: center; width: 1em; height: 1em; border: 1px solid currentColor; background: transparent; color: inherit; cursor: pointer; font-size: 1em; line-height: 1; border-radius: 50%; padding: 0; }
.rich-textarea :deep(.ctx-remove:hover), .msg-text :deep(.ctx-remove:hover) { background: rgba(0,0,0,0.06); }
.rich-textarea :deep(.ctx-label), .msg-text :deep(.ctx-label) { display: inline-flex; align-items: center; font-size: 0.95em; color: inherit; line-height: 1; }
.chat-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.toolbar-left { display: flex; align-items: center; gap: 8px; }
.toolbar-right { display: flex; align-items: center; gap: 8px; }
.upload-inline { display: inline-flex; align-items: center; }
.toolbar-left :deep(.el-upload){ display: inline-flex; align-items: center; }
.toolbar-left :deep(.el-upload .el-button){ margin-top: 0; }
.editor-card { height: 100%; display: flex; flex-direction: column; margin: -16px; border: none; box-shadow: none; flex: 1 1 auto; }
.editor-card :deep(.el-card__header){ padding-bottom: 8px; }
.editor-card :deep(.el-card__body){ padding-top: 8px; display: flex; flex-direction: column; min-height: 0; flex: 1; }
@media (max-width: 768px) { .editor-card { margin: -12px; } }

/* 预览模式结构样式（参考模板详细页） */
.panel-actions { display: flex; align-items: center; gap: 8px; }
.report-preview { display: flex; flex-direction: column; gap: 12px; flex: 1; min-height: 0; overflow: auto; border: 1px solid #ebeef5; border-radius: 6px; padding: 8px; background: #fff; }
.title-row { display: flex; align-items: center; gap: 6px; cursor: pointer; }
.caret { color: #666; }
.section { padding-bottom: 8px; border-bottom: 1px dashed #ddd; }
.section.l2 { padding-left: 18px; }
.section.l3 { padding-left: 36px; }
.h1 { font-size: 20px; font-weight: 700; }
.h2 { font-size: 18px; font-weight: 600; }
.h3 { font-size: 16px; font-weight: 500; }
@media (max-width: 1024px){
  .chat-sidenav { width: 100%; min-width: unset; }
  .gen-layout { flex-direction: column; }
}
</style>
